package concurrent;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class BlockWordsReader {

    private InputStream inputStream;

    public BlockWordsReader(String file) throws FileNotFoundException {
        this.inputStream = new FileInputStream(file);
    }

    public static void main(String[] args) throws IOException {


        BlockWordsReader blockWordsReader = new BlockWordsReader("d:/a.txt");
        PrintStream out = new PrintStream("d:/b.txt");
        while (true) {
            byte[] bytes = blockWordsReader.nextEndLineBlock();
            if (bytes == null) break;
            out.print(new String(bytes, "UTF-8"));
        }

    }

    private final int  blockSize = 1024;
    private final int forwardSize = 32;
    private byte[] lastBytes;

    public synchronized byte[] nextEndLineBlock() throws IOException {
        byte[] oldLastBytes = lastBytes;
        byte[] bytes = new byte[blockSize];
        int len = inputStream.read(bytes, 0, blockSize);

        if (len == -1) return null;
        byte[] result;
        int offset = 0;
        if (len < bytes.length || isWordsBounds(bytes[len - 1])) {
            if (oldLastBytes != null) {
                int oldLen = oldLastBytes.length;
                result = new byte[oldLen + len];
                System.arraycopy(oldLastBytes, 0, result, 0, oldLen);
                lastBytes = null;
                offset += oldLen;

            } else {
                result = new byte[len];
            }
            System.arraycopy(bytes, 0, result, offset, len);
            return result;
        }

        List<byte[]> list = new ArrayList<>();
        int size = 0;
        int read;

        out:
        while (true) {
            byte[] little = new byte[forwardSize];
            read = inputStream.read(little, 0, forwardSize);
            if (read == -1) break;

            list.add(little);
            if (read < forwardSize) {
                size += read;
                break;
            }
            for (int j = 0; j < forwardSize; j++) {
                if (isWordsBounds(little[j])) {
                    read = j + 1;
                    if (j < forwardSize - 1) {
                        lastBytes = new byte[forwardSize - j - 1];
                        System.arraycopy(little, j + 1, lastBytes, 0, lastBytes.length);
                    }
                    size += read;
                    break out;
                }
            }
            size += read;
        }


        if (oldLastBytes != null) {
            int oldLen = oldLastBytes.length;
            result = new byte[oldLen + len + size];
            System.arraycopy(oldLastBytes, 0, result, offset, oldLen);
            if(oldLastBytes==lastBytes){
                lastBytes = null;
            }
            offset += oldLen;
        } else {
            result = new byte[len + size];
        }

        System.arraycopy(bytes, 0, result, offset, len);
        offset += len;
        int i = 0;
        for (; i < list.size() - 1; i++) {
            System.arraycopy(list.get(i), 0, result, offset, forwardSize);
            offset += forwardSize;
        }
        if (read > -1) {
            System.arraycopy(list.get(i), 0, result, offset, read);
        }
        return result;

    }

    private boolean isWordsBounds(byte b) {
        return b == ' ' || b == '\r' || b == '\n' || b == '\t' || b == '\f';

    }
}